package com.echo.im.engin.event;

import com.echo.im.common.contant.RedisConstants;
import com.echo.im.engin.event.entity.UserOfflineEvent;
import com.echo.im.engin.event.entity.UserOnlineEvent;
import com.echo.im.engin.event.entity.UserSessionRenewalEvent;
import com.echo.im.engin.netty.IMServerGroup;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

/**
 * 用户上线服务器不负责给好友推送消息，但是用户下线服务器可以推送
 * 因为用户上线可以自己推送，但是也比较困难，因为要推送给用户的所有在线好友
 * 其实也可以不推送给在线所有好友，直接广播，收不到消息就算了，直接丢弃，也不失为一种办法
 * 但是用户下线的时候自己没办法推送
 * @author echo
 */
@Component
@RequiredArgsConstructor
public class UserEventListener {

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 用户上线
     * @param event
     */
    @EventListener
    public void onUserOnline(UserOnlineEvent event) {

        Long userId = event.getUserId();
        Integer terminal = event.getTerminal();

        // 上报redis
        String key = String.join(":", RedisConstants.IM_USER_STATUS_NAME, userId.toString());
        redisTemplate.opsForHash().put(key, terminal.toString(), IMServerGroup.serverId);

        // 发布事件，方便im-platform更新本地缓存
        redisTemplate.convertAndSend(RedisConstants.IM_USER_STATUS_CHANNEL, userId);
        // 60秒过期
        redisTemplate.expire(key, 60, TimeUnit.SECONDS);

        System.out.println("User Online: " + event.getUserId());

    }

    /**
     * 用户下线
     * @param event
     */
    @EventListener
    public void onUserOffline(UserOfflineEvent event) {
        Long userId = event.getUserId();
        Integer terminal = event.getTerminal();

        // TODO 应该改为lua操作，删除的时候验证serverId是否和当前的一样
        // 删除 key
        String key = String.join(":", RedisConstants.IM_USER_STATUS_NAME, userId.toString());
        redisTemplate.opsForHash().delete(key,terminal.toString());

        // 发布事件，方便 im-platform 更新本地缓存
        redisTemplate.convertAndSend(RedisConstants.IM_USER_STATUS_CHANNEL, userId);

        System.out.println("User Offline: " + event.getUserId());
    }

    /**
     * 用户session续期
     * 极端情况下会出现
     * 1. 服务器重启，不能即时清除redis已经存在的用户信息，需要保证即时清除，所以有自动心跳续期机制
     * 2. 因为此续期是给用户所有设备共同续期，可能存在一个设备在线，但另外一个设备其实已经掉线的情况
     * 3. 这种情况暂时不做考虑，因为这种情况只会发生在我们的netty服务器异常关闭未及时清除用户状态的情况
     * @param event
     */
    @EventListener
    public void onUserSessionRenewal(UserSessionRenewalEvent event) {

        Long userId = event.getUserId();
        // 更新key
        String key = String.join(":", RedisConstants.IM_USER_STATUS_NAME, userId.toString());
        redisTemplate.expire(key, 60, TimeUnit.SECONDS);
    }

}